﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using FastNET.CleanAct.Client.ManagerEngineBusiness.DataObjects;
using FastNET.CleanAct.Common.Repository;

namespace FastNET.CleanAct.Tools.HomeTemplateEditor.Forms
{
    internal partial class PackageBox : Form
    {
        private IList<Package> _packages;
        private Package _selectedPackage;
        private bool _isListRefreshing;
        private bool _isLoadingData;
        private bool _isModified;
        private bool _isAdding;
        private int _addIndex = -1;

        public PackageBox()
        {
            InitializeComponent();
            _selectedPackage = null;

        }

        private void PackageBox_Load(object sender, EventArgs e)
        {
            _packages = Package.Retrieve();

            LoadList();

            _selectedPackage =
                (from item in _packages where item.ID == ((PackageListItem)PackageList.SelectedItem).ID select item).FirstOrDefault();

            LoadData();

        }

        private void PackageList_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (_isLoadingData || _isListRefreshing || PackageList.SelectedItem == null)
            {
                return;
            }

            PackageListItem? lastItem = null;

            if (_selectedPackage != null)
            {
                lastItem = new PackageListItem { ID = _selectedPackage.ID, Name = _selectedPackage.Name };
            }

            _selectedPackage = (from item in _packages where item.ID == ((PackageListItem)PackageList.SelectedItem).ID select item).FirstOrDefault();

            //Reset the adding stage
            if (_isAdding && ((PackageListItem)PackageList.SelectedItem).ID != Guid.Empty)
            {
                PackageList.Items.RemoveAt(_addIndex);
                AddButton.Enabled = true;
                _isAdding = false;
            }

            if (lastItem.HasValue)
            {
                MarkModified(lastItem.Value, false);
            }

            LoadData();
            ErrorProvider.Clear();
        }



        private void LoadList()
        {
            if (_isListRefreshing)
            {
                return;
            }

            PackageList.BeginUpdate();
            _isListRefreshing = true;
            PackageList.Items.Clear();
            foreach (Package package in _packages)
            {
                PackageList.Items.Add(new PackageListItem { ID = package.ID, Name = package.Name });
            }

            PackageList.DisplayMember = "Name";
            if (PackageList.Items.Count > 0)
            {
                PackageList.SelectedIndex = 0;
            }

            _isListRefreshing = false;
            PackageList.EndUpdate();
        }

        private void MarkModified(PackageListItem packageItem, bool state)
        {
            if (_isListRefreshing || _selectedPackage == null)
            {
                return;
            }

            PackageList.BeginUpdate();
            _isListRefreshing = true;

            int modifiedIndex = -1;

            foreach (PackageListItem item in PackageList.Items)
            {
                if (item.ID !=
                    packageItem.ID)
                {
                    continue;
                }
                modifiedIndex = PackageList.Items.IndexOf(item);
                break;
            }

            if (modifiedIndex > -1)
            {
                PackageList.Items[modifiedIndex] = state ?
                    new PackageListItem { ID = packageItem.ID, Name = packageItem.Name + " *" } :
                    new PackageListItem { ID = packageItem.ID, Name = packageItem.Name };
            }

            _isListRefreshing = false;
            PackageList.EndUpdate();
        }

        private void UpdateNewPackage(PackageListItem packageItem)
        {
            if (_isListRefreshing || _selectedPackage == null)
            {
                return;
            }

            PackageList.BeginUpdate();
            _isListRefreshing = true;

            int modifiedIndex = -1;

            foreach (PackageListItem item in PackageList.Items)
            {
                if (item.ID !=
                    Guid.Empty)
                {
                    continue;
                }
                modifiedIndex = PackageList.Items.IndexOf(item);
                break;
            }

            if (modifiedIndex > -1)
            {
                PackageList.Items[modifiedIndex] = new PackageListItem { ID = packageItem.ID, Name = packageItem.Name };
            }

            _isListRefreshing = false;
            PackageList.EndUpdate();
        }





        private void Version_KeyPress(object sender, KeyPressEventArgs e)
        {
            string keyInput = e.KeyChar.ToString();

            if (Char.IsDigit(e.KeyChar))
            {
                // Digits are OK
            }
            else if (e.KeyChar == '\b')
            {
                // Backspace key is OK
            }
            else
            {
                // Consume this invalid key and beep
                e.Handled = true;
                //    MessageBeep();
            }
        }

        private void Field_TextChanged(object sender, EventArgs e)
        {
            if (_isLoadingData || _isModified || _isListRefreshing || _selectedPackage == null)
            {
                return;
            }

            _isModified = true;
            SaveButton.Enabled = true;

            if (_isAdding)
            {
                MarkModified(new PackageListItem { ID = Guid.Empty, Name = "(New Package)" }, true);
            }
            else
            {
                MarkModified(new PackageListItem { ID = _selectedPackage.ID, Name = _selectedPackage.Name }, true);
            }

        }

        #region Save/Load

        private void LoadData()
        {
            if (_selectedPackage == null || _isLoadingData)
            {
                return;
            }
            _isLoadingData = true;

            NameValue.Text = _selectedPackage.Name;
            PublisherValue.Text = _selectedPackage.Publisher;
            DateCreatedValue.Text = _selectedPackage.DateCreated.ToLocalTime().ToString();
            VersionBuildValue.Text = _selectedPackage.Version.Build.ToString();
            VersionMajorValue.Text = _selectedPackage.Version.Major.ToString();
            VersionMinorValue.Text = _selectedPackage.Version.Minor.ToString();
            VersionRevisionValue.Text = _selectedPackage.Version.Revision.ToString();

            SaveButton.Enabled = false;
            _isModified = false;
            _isLoadingData = false;
        }

        private void ClearData()
        {
            NameValue.Text = String.Empty;
            PublisherValue.Text = String.Empty;
            DateCreatedValue.Text = String.Empty;
            VersionBuildValue.Text = String.Empty;
            VersionMajorValue.Text = String.Empty;
            VersionMinorValue.Text = String.Empty;
            VersionRevisionValue.Text = String.Empty;
        }

        private void SaveData()
        {
            if (_selectedPackage == null)
            {
                return;
            }

            _selectedPackage.Name = NameValue.Text;
            _selectedPackage.Publisher = PublisherValue.Text;
            _selectedPackage.Version =
                new Version(VersionMajorValue.Text + "." + VersionMinorValue.Text + "." +
                            VersionBuildValue.Text + "." + VersionRevisionValue.Text);

            _selectedPackage.Save();

            SaveButton.Enabled = false;
            _isModified = false;
        }

        #endregion

        #region Form Buttons

        private void SaveButton_Click(object sender, EventArgs e)
        {
            if (!IsVersionValid() || !IsNameValid())
            {
                MessageBox.Show(this,
                                "One or more values are incorrect. Please correct the issues and try again.",
                                "Field Validation",
                                MessageBoxButtons.OK,
                                MessageBoxIcon.Warning);
                return;
            }

            SaveData();

            if (_isAdding)
            {
                UpdateNewPackage(new PackageListItem { ID = _selectedPackage.ID, Name = _selectedPackage.Name });
                _packages.Add(_selectedPackage);
                _isAdding = false;
            }
            else
            {
                MarkModified(new PackageListItem { ID = _selectedPackage.ID, Name = _selectedPackage.Name }, false);
            }

            AddButton.Enabled = true;
            ErrorProvider.Clear();
        }

        private void CloseButton_Click(object sender, EventArgs e)
        {
            Close();
        }

        private void AddButton_Click(object sender, EventArgs e)
        {
            if (_isAdding)
            {
                return;
            }

            _isAdding = true;
            PackageListItem item = new PackageListItem { ID = Guid.Empty, Name = "(New Package)" };

            PackageList.Items.Add(item);
            _addIndex = PackageList.Items.IndexOf(item);
            PackageList.SelectedIndex = _addIndex;

            _selectedPackage = new Package();
            LoadData();
            AddButton.Enabled = false;
            ErrorProvider.Clear();
        }

        private void RemoveButton_Click(object sender, EventArgs e)
        {
            if (_selectedPackage == null)
            {
                return;
            }

            if (!_selectedPackage.IsNew)
            {
                _selectedPackage.Delete();
            }
            _isAdding = false;
            AddButton.Enabled = true;

            _packages = Package.Retrieve();
            LoadList();
            _selectedPackage =
                (from item in _packages where item.ID == ((PackageListItem)PackageList.SelectedItem).ID select item).FirstOrDefault();

            if (_selectedPackage != null)
            {
                LoadData();
            }
            else
            {
                ClearData();
            }
            ErrorProvider.Clear();
        }

        #endregion

        #region Validating Events

        private void Version_Validating(object sender, System.ComponentModel.CancelEventArgs e)
        {
            IsVersionValid();
        }

        private void NameValue_Validating(object sender, System.ComponentModel.CancelEventArgs e)
        {
            IsNameValid();
        }

        #endregion

        #region Validations

        private bool IsVersionValid()
        {
            bool isValid = true;

            if (String.IsNullOrEmpty(VersionMajorValue.Text))
            {
                ErrorProvider.SetError(VersionMajorValue, "Version Major value cannot be empty");
                isValid = false;
            }
            else
            {
                ErrorProvider.SetError(VersionMajorValue, string.Empty);
            }

            if (String.IsNullOrEmpty(VersionMinorValue.Text))
            {
                ErrorProvider.SetError(VersionMinorValue, "Version Minor value cannot be empty");
                isValid = false;
            }
            else
            {
                ErrorProvider.SetError(VersionMinorValue, string.Empty);
            }

            if (String.IsNullOrEmpty(VersionBuildValue.Text))
            {
                ErrorProvider.SetError(VersionBuildValue, "Version Build value cannot be empty");
                isValid = false;
            }
            else
            {
                ErrorProvider.SetError(VersionBuildValue, string.Empty);
            }

            if (String.IsNullOrEmpty(VersionRevisionValue.Text))
            {
                ErrorProvider.SetError(VersionRevisionValue, "Version Revision value cannot be empty");
                isValid = false;
            }
            else
            {
                ErrorProvider.SetError(VersionRevisionValue, string.Empty);
            }

            return isValid;
        }

        private bool IsNameValid()
        {
            if (String.IsNullOrEmpty(NameValue.Text))
            {
                ErrorProvider.SetError(NameValue, "Name value cannot be empty");
                return false;
            }

            ErrorProvider.SetError(NameValue, string.Empty);
            return true;
        }

        #endregion

        #region Private Structures

        private struct PackageListItem
        {
            public string Name { get; set; }
            public Identity ID { get; set; }
        }

        #endregion
    }
}
